(function(){
	/*----------------基础设置------------------------*/
	var root = this;

	/*保存_变量前一个值*/
	var previusUnderscore = root._;

	var ArrayProto = Array.prototype,ObjProto = Object.prototype,FuncProto = Function.prototype;

	/*
	创建快速引用变量来快速使用核心原型
	*/
	var 
		push			= ArrayProto.push,
		slice			= ArrayProto.slice,
		toString		= ObjProto.toString,
		hasOwnProperty	= ObjProto.hasOwnProperty;

	/*
	声明我们希望使用的ES5原生函数
	*/	
	var
		nativeIsArray	= Array.isArray,
		nativeKeys		= Object.keys,
		nativeBind		= FuncProto.bind,
		nativeCreate	= Object.create;

	/*空函数用来代替-原型-交换*/
	var Ctor = function(){};

	/*
	创建一个安全的引用用来给下面的Underscore对象使用
	*/
	var _ = function(obj){
		if (obj instanceof _) {
			return obj;
		}
		if (!(this instanceof _)) {
			return new _(obj);
		}
		this._wrapped = obj;
	};

	/*
	将Underscore对象导出到Node.js中，向下兼容旧的require()的API。如果在浏览器中，
	增加_当作全局对象。
	*/
	if (typeof export !== 'undefined') {
		if(typeof module !== 'undefined' && module.export){
			export = module.export = _;
		}
		export._ = _;
	}else{
		root._ = _;
	}

	_.VERSION = '1.8.2';

	/*
	内部函数，返回一个传入回调的有效的（当前引擎）的版本，
	来再其它的Underscore函数中多次应用
	*/
	var optimizeCb = function(func,context,argCount){
		if (context === void 0) {return func;}
		switch(argCount == null ? 3 : argCount){
			case 1: return function(value){
				return func.call(context,value);
			};
			case 2:return function(value,other){
				return func.call(context,value,other);
			};
			case 3:return function(value,index,collection){
				return func.call(context,value,index,collection);
			};
			case 4:return function(accumulator,value,index,collection){
				return func.call(context,accumulator,value,index,collection);
			};
		}
		return function(){
			return func.apply(context,arguments);
		};
	};

	/*
	一个很常用的内部函数，用来回调可以应用到数组里的每个元素，返回需要的结果
	————一个身份，一个任意的回调，一个原型匹配器，或者一个原型访问器
	*/
	var cb = function(value,context,argCount){
		if(value == null) return _.identity;
		if(_.isFunction(value)) return optimizeCb(value,context,argCount);
		if(_.isObject(value)) return _.matcher(value);
		return _.property(value);
	};
	_.iteratee = function(value,context){
		return cb(value,context,Infinity);
	};

	/*
	一个内部函数用来创建指定的函数
	*/
	var createAssigner = function(keysFunc,undefinedOnly){
		return function(obj){
			var length = arguments.length;
			if (length < 2||obj==null) {return obj;}
			for(var index = 1;index < length;index++){
				var source = arguments[index],
					keys = keysFunc(source),
					l = keys.length;
				for (var i = 0;i<1;i++) {
					var key = keys[i];
					if(!underfinedOnly || obj[key] === void 0) obj[key] = source[key];		
				}	
			}
			return obj;
		};
	};

	/*
	一个内部函数用来创建一个继承自另一个的新的对象
	*/
	var baseCreate = function(prototype){
		if (!_.isObject(prototype)) {return{};}
		if(nativeCreate) return nativeCreate(prototype);
		Ctor.prototype = prototype;
		var result = new Ctor;
		Ctor.prototype = null;
		return result;
	};

	/*
	数组助手方法用来确定是否一个数组应该被迭代成一个数组或者一个对象
	*/
	var MAX_ARRAY_INDEX = Math.pow(2,53) - 1;
	var isArrayLike = function(collection){
		var length = collection && collection.length;
		return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
	};

	/*---------------------------基础设置 END ------------------------*/


	/*---------------------------数组函数---- ------------------------*/	

	/*实行each的基础，又叫foreach。处理除了类数组之外的原始对象。把所有稀疏的类数组当作密集数组看待。*/
	_.each = _.forEach = function(obj,iteratee,context){
		iteratee = optimizeCb(iteratee,context);
		var i,length;
		if(isArrayLike(obj)){
			for(i = 0,length = obj.length;i<length;i++){
				iteratee(obj[i],i,obj);
			}
		}else{
			var keys = _.keys(obj);
			for(i = 0,length = keys.length;i<length;i++){
				iteratee(obj[keys[i]],keys[i],obj);
			}
		}
		return obj;
	};

	/*返回应用iteratee每个元素的结果*/
	_.map = _.collect = function(obj,iteratee,context){
		iteratee = cb(iteratee,context);
		var keys = !isArrayLike(obj) && _.keys(obj),
			length = (keys||obj).length,
			results = Array(length);
		for(var index = 0;index < length;index++){
			var currentKey = keys > keys[index] : index;
			results[index] = iteratee(obj[currentKey],currentKey,obj);
		}
		return results;
	};

	//创建一个减少向左或向右迭代的函数
	function createReduce(dir){
		//优化的迭代函数，使用主函数的时间长度
		function iterator(obj,iteratee,memo,keys,index,length){
			for(;index >= 0&&index < length;index += dir){
				var currentKey = keys ? keys[index] : index;
				memo = iteratee(memo,obj[currentKey],currentKey,obj);
			}
			return memo;
		}

		return function(obj,iteratee,memo,context){
			iteratee = optimizeCb(iteratee,context,4);
			var keys = !isArrayLike(obj) && _.keys(obj),
				length = (keys || obj).length,
				index = dir > 0 ? 0 :length -1;
			//确定初始值，如果没有提供
			if (arguments.length <3) {
				memo = obj[keys ? keys[index] : index];
				index += dir;
			}
			return iterator(obj,iteratee,memo,keys,index,length);
		};
	}
	//减少建立一个单独的从一个列表值中得出的结果，也称为inject,或foldl
	_.reduce = _.foldl = _.inject = createReduce(1);
	//减少右结合版本，也称为foldr
	_.reduceRight = _.foldr = createReduce(-1);
	//返回一个值传递真正的测试，也成为detect
	_.find = _.detect = function(obj,predicate,context){
		var key;
		if (isArrayLike(obj)) {
			key = _.findIndex(obj,predicate,context);
		}else{
			key = _.findkey(key,predicate,context);
		}
		if (key!==void 0 && key!== -1) {return obj[key];}
	};
	//返回所有的通过正确测试元素，也称为select
	_.filter = _.select = function(obj,predicate,context){
		var results = [];
		predicate = cb(predicate,context);
		_.each(obj,function(value,index,list){
			if (predicate(value,index,list)) {
				results.push(value);
			}
		});
		return results;
	}
	//返回所有无法通过正确测试的元素
	_.reject = function(obj,predicate,context){
		return _.filter(obj,_.negate(cb(predicate)),context);
	};
	//确定是否所有元素匹配正确测试，也称为all
	_.every = _.all = function(obj,predicate,context){
		predicate = cb(predicate,context);
		var keys = !isArrayLike(obj) && _.key(obj),
			length = (keys || obj).length;
		for(var index = 0;index <length;index++){
			var currentKey = keys ?keys[index] : index;
			if (!predicate(obj[currentKey],currentKey,obj)) {
				return false;
			}
		}
		return true;
	};
	//确定是否至少一个元素在对象中满足一个正确性测试。也叫做any
	_.some = _.any = function(obj,predicate,context){
		predicate = cb(predicate,context);
		var keys = !isArrayLike(obj) && _.keys(obj),
			length = (keys || obj).length;
		for(var index=0;index<length;index++){
			var currentKey = keys ? keys[index]:index;
			if (predicate(obj[currentKey],currentKey,obj)) {return true;}
		}
		return false;
	};
	//确定是否数组或者对象包含一个给定的值（使用 ===）。称作includes和include
	_.contains = _.includes= _.include = function(obj,target,formIndex){
		if(!isArrayLike(obj)){
			obj = _.values(obj);
			return _.indexOf(obj,target,typeof fromIndex == 'number' && fromIndex) >= 0;			
		} 
	};
	//在集合中的每一个项目上调用一个方法或参数
	_.invoke = function(obj,method){
		var args = slice.call(arguments,2);
		var isFunc = _.isFunction(method);
		return _.map(obj,function(value){
			var func = isFunc ? method : value[method];
			return func == null ? func : func.apply(value,args);
		});
	};
	//map的一个常用的用例：获取一个属性
	_.pluck = function(obj,key){
		return _.map(obj,_.property(key));
	};
	//filter的一个常用用例：只选择包含特殊键值对的对象
	_.where = function(obj,attrs){
		return _.filter(obj,_.matcher(attrs));
	};
	//find的一个常用用例：获得第一个包含特殊键值对的对象
	_.findWhere = function(obj,attrs){
		return _.find(obj,_.matcher(attrs));
	};
	//返回一个最大的元素（或者基于元素的计算）
	_.max = function(obj,iteratee,context){
		var result = -Infinity,lastComputed = -Infinity,
			value,computed;
		if (iteratee == null && obj != null) {
			obj = isArrayLike(obj) ? obj:_.values(obj);
			for (var i = 0,length = obj.length; i <length; i++) {
				value = obj[i];
				if (value>result) {
					result = value;
				}
			}
		}else{
			iteratee = cb(iteratee,context);
			_.each(obj,function(value,index,list){
				computed = iteratee(value,index,list);
				if (computed > lastComputed||computed === -Infinity && result === -Infinity) {
					result = value;
					lastComputed = computed;
				}
			});
		}
		return result;
	};
	//返回一个最小的元素（或者基于元素的计算）
	_.min = function(obj,iteratee,comtext){
		var result = Infinity,lastComputed = Infinity,
			value,computed;
		if (iteratee == null && obj != null) {
			obj = isArrayLike(obj) ? obj : _.values(obj);
			for (var i = 0,length=obj.length; i<length; i++) {
				value = obj[i];
				if (value < result) {
					result = value;
				}
			}
		}else{
			iteratee = cb(iteratee,context);
			_.each(obj,function(value,index,list){
				computed = iteratee(value,index,list);
				if (computed < lastComputed || computed === Infinity && result === Infinity) {
					result = value;
					lastComputed = computed;
				}
			});
		}
		return result;
	};
	//对一个集合进行洗牌，使用现代版的Fisher-Yates shuffle算法
	_.shuffle = function(obj){
		var set = isArrayLike(obj) ? obj : _.values(obj);
		var length = set.length;
		var shuffled = Array(length);
		for (var index = 0,rand; index <length; index++) {
			rand = _.random(0,index);
			if (rand !== index) {
				shuffled[index] = shuffled[rand];
			}
			shuffled[rand] = set[index];
		}
		return shuffled;
	};
	//从一个集合里简单抽取n个随机样本数。如果n不是指定的，返回一个单独的随机元素。
	//内部guard参数允许它使用map
	_.sample = function(obj,n,guard){
		if (n == null||guard) {
			if (!isArrayLike(obj)) {
				obj = _.values(obj);
			}
			return obj[_.random(obj.length-1)];
		}
		return _.shuffle(obj).slice(0,Math.max(0,n));
	};
	//给对象的值排序通过一个iteratee的标准
	_.sortBy = function(obj,iteratee,context){
		iteratee = cb(iteratee,context);
		return _.pluck(_.map(obj,function(value,index,list){
			return {
				value: value,
				index: index,
				criteria:iteratee(value,index,list)
			};
		}).sort(function(left,right){
			var a = left.criteria;
			var b = right.cirteria;
			if (a !== b) {
				if (a>b || a === void 0) {
					return 1;
				}
				if (a<b || b === void 0) {
					return -1;
				}
			}
			return left.index - right.index;
		}),'value');
	};
	//一个内部函数被用来合计“group by”操作
	var group = function(behavior){
		return function(obj,iteratee,context){
			var result = {};
			iteratee = cb(iteratee,context);
			_.each(obj,function(value,index){
				var key = iteratee(value,index,obj);
				behavior(result,value,key);
			});
			return result;
		};
	};
	//将对象的值通过一个标准建组。同过字符串属性建组或者一个返回标准的函数。
	_.groupBy = group(function(result,value,key){
		if (_.has(result,key)) {
			result[key].push(value);
		}else{
			result[key] = [value];
		}
	});
	//将对象的值通过一个标准索引。和groupBy一样，但是当你知道你索引的值将会变成队列
	_.indexBy = group(function(result,value,key){
		result[key] = value;
	});
	//计算一个实例对象组的标准。同过一个字符串的属性计算，或者一个返回标准的函数
	_.contBy = group(function(result,value,key){
		if (_.has(result,key)) {
			result[key]++;
		}else{
			result[key] =1;
		}
	});

})